#include <iostream>
#include <QDebug>
#include "node.h"
#include "connection.h"
#include "graph.h"

Graph::Graph(uint32 size) : nodes_(size), nodeConnections_(size)
{

}

Graph::~Graph()
{
	//delete each node
	for(size_t i=0; i<nodes_.size();++i)
	{
		//delete node connections
		for (AdjacentConnections::iterator it = nodeConnections_[i].begin(); it != nodeConnections_[i].end(); ++it) {
			delete *it;
		}	
		nodeConnections_[i].clear();
		delete nodes_[i];
	}
	nodes_.clear();
	nodeConnections_.clear();

	//TODO: clean connections
}

Node* Graph::getNode(const uint32 id) const
{
	if(id >= 0 && id < nodes_.size())
	{
		return nodes_[id];
	} 
	else
	{
		return NULL;
	}
}

void Graph::addNode(Node* newNode)
{
	if(newNode->getID() >= 0)
	{
		nodes_[newNode->getID()] = newNode;
		nodeConnections_[newNode->getID()] = AdjacentConnections();
		std::cout << "Added Node: " << newNode->getID() << std::endl;
	}
}

void Graph::addConnection(Connection* connection)
{
	//check if From & To nodes exist
	if(connection->getFromNode() < nodes_.size() && connection->getToNode() < nodes_.size())
	{	
		//make sure the connection is unique
		if(isConnectionUnique(connection->getFromNode(), connection->getToNode()))
		{
			nodeConnections_[connection->getFromNode()].push_back(connection);
			std::cerr << "Established connection between Node " 
				<< connection->getFromNode() << " and Node " << connection->getToNode() << std::endl;
		}
	}
	else
	{
		std::cerr << "Error while attempting to add connection between Node " 
			<< connection->getFromNode() << " and Node " << connection->getToNode() << std::endl;
	}
}

//returns the connections from a given node
Graph::AdjacentConnections Graph::getConnections(uint32 nodeId) const
{
	//check if requested node is valid
	if(nodeId >= 0 && nodeId < nodes_.size())
	{
		return nodeConnections_[nodeId];
	}
	else
	{
		AdjacentConnections empty;
		return empty;
	}
}

//returns the total number of active nodes
const uint32 Graph::getNodeAmount()
{
	uint32 counter = 0;

	for(size_t i=0;i<nodes_.size();i++)
	{
		if(nodes_[i]->isActive())
			++counter;
	}
	return counter;
}

//returns the total number of connections
const uint32 Graph::getConnectionAmount()
{
	uint32 counter = 0;
	for(size_t i=0;i<nodeConnections_.size();i++)
	{
		counter += nodeConnections_[i].size();
	}
	return counter;
}

bool Graph::isConnectionUnique(uint32 from, uint32 to)
{
	AdjacentConnections::const_iterator connectionsIt;

	//iterate through all connections of the From node
	for(connectionsIt = nodeConnections_[from].begin();
		connectionsIt != nodeConnections_[from].end();
		++connectionsIt)
	{
		//check if there is already the same connection
		if((*connectionsIt)->getToNode() == to)
		{
			return false;
		}
	}
	return true;
}